雙指針技術是競賽與面試中極常出現的技巧,適用於處理:
範例邏輯:
int left = 0, right = nums.size() - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) return true;
else if (sum < target) left++;
else right--;
}
類型 | 說明 | 常見應用 |
---|---|---|
對撞型 Two-End | 左右指針由兩端向中間靠攏 | 排序陣列中找總和為目標的兩數/三數 |
滑動窗口 Sliding Window | 左右指針共同控制一個區間,右擴左縮 | 區間和、最短/最長子陣列、總數 |
原題:
https://cses.fi/problemset/task/1084
題意:
有 n 位申請人與 m 間公寓,每位申請人希望租的房間大小為 xi,每間公寓實際大小為 yj,只要誤差在 k 以內(|xi-yj|≤k)即可配對。
解題思路:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m, k;
cin >> n >> m >> k;
vector<int> applicants(n), apartments(m);
for (int &x : applicants) cin >> x;
for (int &y : apartments) cin >> y;
sort(applicants.begin(), applicants.end());
sort(apartments.begin(), apartments.end());
int i = 0, j = 0, count = 0;
while (i < n && j < m) {
if (abs(applicants[i] - apartments[j]) <= k) {
count++;
i++, j++;
} else if (apartments[j] < applicants[i] - k) {
j++;
} else {
i++;
}
}
cout << count << "\n";
return 0;
}
原題:
https://cses.fi/problemset/task/1640
題意:
給定長度為 n 的陣列與目標值 x,找出陣列中是否有兩個不同的數 a+b=x,並輸出其原始位置(1-indexed)。
解題思路:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, x;
cin >> n >> x;
vector<pair<int,int>> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i].first;
a[i].second = i+1; // 儲存原始 index
}
sort(a.begin(), a.end());
int l = 0, r = n-1;
while (l<r) {
int sum = a[l].first + a[r].first;
if (sum == x) {
cout << a[l].second << " " << a[r].second << "\n";
return;
} else if (sum < x) l++;
else r--;
}
cout << "IMPOSSIBLE\n";
return 0;
}
原題:
https://leetcode.com/problems/3sum/description/
題意:
給定整數陣列 nums,找出所有不重複的三元組 a + b + c = 0。
解題思路:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i-1]) continue;
int left = i+1, right = nums.size()-1;
while (left<right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum==0) {
res.push_back({nums[i], nums[left], nums[right]});
while (left<right && nums[left] == nums[left+1]) left++;
while (left<right && nums[right] == nums[right-1]) right--;
left++; right--;
}
else if (sum<0) left++;
else right--;
}
}
return res;
}
};
原題:
https://leetcode.com/problems/minimum-size-subarray-sum/description/
題意:
給定正整數陣列與目標值 target,求連續子陣列總和 ≥ target 的 最短長度,若無解回傳 0。
解題思路:滑動窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0, sum = 0, res = INT_MAX;
for (int right=0; right < nums.size(); right++) {
sum += nums[right];
while (sum >= target) {
res = min(res, right-left+1);
sum-=nums[left++];
}
}
return res == INT_MAX ? 0 : res;
}
};